package com.jic.filter;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.jic.config.ConstantClassField;
import com.jic.entity.AdminOperate;
import com.jic.enums.DeptTypeEnums;
import com.jic.enums.RedisKeyEnums;
import com.jic.utils.RedisManager;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.HttpServletRequestWrapper;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

//import com.jic.entity.AdminOperate;
//import com.jic.enums.DeptTypeEnums;
//import com.jic.enums.RedisKeyEnums;

@Component
@Slf4j
public class AccessFilter extends ZuulFilter {

    private final static String USER_NOT_AUTHORITY = "4000";

    private final static String ADMIN_PLATFORM_SIGN = "admin";

    private final static String H5_PLATFORM_SIGN = "h5";

    private final static String REQUEST_PLATFORM_SIGN_KEY = "clt";

    private final static String REQUEST_AUTHORITY_SIGN_KEY = "token";

    private final static String POST_REQUEST_TYPE = "POST";

    @Value("${white_list}")
    private String white_list;

    @Resource
    private RedisManager redisManager;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }
    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    private final static List<String> ACCESS_JSON_SERVER = Lists.newArrayList("jic-market", "jic-manager","jic-data");
    @Override
    public Object run() throws ZuulException {
        //获取请求的上下文类 注意是：com.netflix.zuul.context包下的
        RequestContext ctx = RequestContext.getCurrentContext();
        //获取request对象
        HttpServletRequest request = ctx.getRequest();
        //避免中文乱码
        ctx.addZuulResponseHeader("Content-type", "text/json;charset=UTF-8");
        ctx.getResponse().setCharacterEncoding("UTF-8");
        ctx.getResponse().setHeader("Access-Control-Allow-Origin", "*");
        ctx.getResponse().setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        ctx.getResponse().setHeader("Access-Control-Max-Age", "3600");
        ctx.getResponse().setHeader("Access-Control-Allow-Headers", "x-requested-with");

        ACCESS_JSON_SERVER.stream().filter(x->{
            return request.getRequestURI().contains(x);
        }).findAny().ifPresent(y->{
            ctx.addZuulRequestHeader("Content-type","application/json;charset=UTF-8");
            ctx.addZuulResponseHeader("Content-type", "application/json;charset=UTF-8");
        });
        String method = request.getMethod();
        String headerClt = request.getParameter(REQUEST_PLATFORM_SIGN_KEY);
        request.getContentType();
        // 过滤URI
        if(filterUri(ctx)){
            // 不需要拦截的URI直接放过
            return null;
        }
        // H5端不做处理
        if(H5_PLATFORM_SIGN.equalsIgnoreCase(headerClt)){
            return null;
        }
        // 目前只处理post请求
        if(StringUtils.equalsIgnoreCase(POST_REQUEST_TYPE,method)) {
            try {
                JSONObject requestEntityJson = fetchRequestBody(ctx);
                boolean isNotAdmin = checkCltIsNotAdmin(requestEntityJson);
                if (isNotAdmin) {
                    // 不是后台Admin请求不做处理
                    return null;
                }
                // 检查token是否有效
                String cacheUserInfo = checkUserTokenIsEmpty(requestEntityJson);
                if (USER_NOT_AUTHORITY.equals(cacheUserInfo)) {
                    // 返回消息
                    ctx.setResponseBody("{\"code\":\"4000\",\"msg\":\"用户未登录\"}");
                    // 对该请求禁止路由，禁止访问下游服务
                    ctx.setSendZuulResponse(false);
                    return null;
                }

                // RequestBody 新增参数
                requestEntityJson = setRequestBodyVal(requestEntityJson, cacheUserInfo);
                String charset = ctx.getRequest().getCharacterEncoding();
                byte[] requestEntityBytes = requestEntityJson.toJSONString().getBytes(charset);
                ctx.setRequest(new HttpServletRequestWrapper(ctx.getRequest()) {
                    @Override
                    public ServletInputStream getInputStream() throws IOException {
                        return new ServletInputStreamWrapper(requestEntityBytes);
                    }
                    @Override
                    public int getContentLength() {
                        return requestEntityBytes.length;
                    }

                    @Override
                    public long getContentLengthLong() {
                        return requestEntityBytes.length;
                    }
                });
            } catch (Exception e) {
                // 返回信息
                ctx.setResponseBody("{\"code\":\"9999\",\"msg\":\"服务暂时不可用\"}");
                // 对该请求禁止路由，禁止访问下游服务
                ctx.setSendZuulResponse(false);
                log.error("Update RequesBody ERROR：{}", ExceptionUtils.getStackFrames(e));
                return null;
            }
        }
        return null;
    }

    /**
     * 过滤 Request URI
     * @param ctx
     * @return
     */
    private boolean filterUri(RequestContext ctx){
        String pathUri = ctx.getRequest().getRequestURI();
        String[] pathArray = white_list.split(",");
        List<String> pathList = Arrays.asList(pathArray);
        if(pathList.contains(pathUri)){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 检查客户端是否是后台Admin
     * @param requestEntityJson
     * @return
     */
    private boolean checkCltIsNotAdmin(JSONObject requestEntityJson){
        if(null == requestEntityJson){
            return true;
        }
        String clt = requestEntityJson.getString(REQUEST_PLATFORM_SIGN_KEY);
        if(StringUtils.isNotEmpty(clt) && StringUtils.equalsIgnoreCase(ADMIN_PLATFORM_SIGN,clt)){
            return false;
        }
        return true;
    }

    /**
     * 检查token是否有效
     * 有效token获取缓存用户信息
     * @param requestEntityJson
     * @return
     * @throws Exception
     */
    private String checkUserTokenIsEmpty(JSONObject requestEntityJson) throws Exception{
        // 获取参数  token
        String token = requestEntityJson.getString(REQUEST_AUTHORITY_SIGN_KEY);
        if (StringUtils.isEmpty(token)) {
            return USER_NOT_AUTHORITY;
        }
        String sysStr = redisManager.getString(token);
        if (StringUtils.isEmpty(sysStr)) {
            return USER_NOT_AUTHORITY;
        }
        return sysStr;

    }


    /**
     * 获取requestBody
     * @param ctx
     * @return
     * @throws Exception
     */
    private JSONObject fetchRequestBody(RequestContext ctx) throws Exception {
        String charset = ctx.getRequest().getCharacterEncoding();
        InputStream in = (InputStream) ctx.get("requestEntity");
        if (null == in) {
            in = ctx.getRequest().getInputStream();
        }
        String requestEntityStr = StreamUtils.copyToString(in, Charset.forName(charset));
        requestEntityStr = URLDecoder.decode(requestEntityStr, charset);
        JSONObject requestEntityJson = JSONObject.parseObject(requestEntityStr);
        return requestEntityJson;
    }



    /**
     * 给RequestBody统一设置值
     * @return
     */
    private JSONObject setRequestBodyVal(JSONObject requestEntityJson, String cacheUserInfo) throws Exception {
        //从redis中获取信息
        Map<String,Object> userMap = JSONArray.parseObject(cacheUserInfo, Map.class);
        String token = requestEntityJson.getString(REQUEST_AUTHORITY_SIGN_KEY);
        //判断用户类型 0运营平台、1 子平台、2 商家、3 店铺
        Integer deptType = Integer.valueOf(userMap.get(ConstantClassField.TYPE).toString());

        AdminOperate adminOperate = new AdminOperate();
//        //下级数据权限
//        if (DeptTypeEnums.STORE_PLATFORM.getName().equals(deptType) || DeptTypeEnums.MERCHANT_PLATFORM.getName().equals(deptType) ||
//                DeptTypeEnums.CHILD_PLATFORM.getName().equals(deptType) ||
//                DeptTypeEnums.OPERATION_PLATFORM.getName().equals(deptType) ){
//            //设置店铺权限
//            String deptIds = getRedisAuthIds(RedisKeyEnums.ADMIN_DEPT_IDS.getName(), token);
//            adminOperate.setDeptIds(JSONArray.parseObject(deptIds,List.class));
//        }
//        //店铺上级商家
//        if(DeptTypeEnums.STORE_PLATFORM.getName().equals(deptType)){
//            String merchantIds = getRedisAuthIds(RedisKeyEnums.ADMIN_MERCHANT_IDS.getName(), token);
//            adminOperate.setMerchantIds(JSONArray.parseObject(merchantIds,List.class));
//        }
//        //商家上级平台
//        if (DeptTypeEnums.MERCHANT_PLATFORM.getName().equals(deptType) ){
//            //设置店铺权限
//            String childrenIds = getRedisAuthIds(RedisKeyEnums.ADMIN_CHILDREN_IDS.getName(), token);
//            adminOperate.setChildIds(JSONArray.parseObject(childrenIds,List.class));
//        }
        //设置deptId
        adminOperate.setDeptId(Long.valueOf(userMap.get(ConstantClassField.DEPT_ID).toString()));
        //设置dept_type
        adminOperate.setDeptType(DeptTypeEnums.getByName(deptType));

        if(userMap.get("deptIds") != null){
            List deptIds = JSONObject.parseObject(JSONObject.toJSONString(userMap.get("deptIds")), List.class);
            adminOperate.setDeptIds(deptIds);
        }

        //设置ref_id
//        adminOperate.setBusinessId(userMap.get(ConstantClassField.BUSINESS_ID) == null ? null : Long.valueOf(userMap.get(ConstantClassField.BUSINESS_ID).toString()));
        //设置token
        adminOperate.setToken(token);
        //设置登录人
        adminOperate.setOperator(Long.valueOf(userMap.get("id").toString()));
        //设置登录人名称
        adminOperate.setOperateName(userMap.get("username").toString());
        //设置adminOperate
        requestEntityJson.put(ConstantClassField.ADMIN_OPERATE,adminOperate);
        return requestEntityJson;
    }

    /**
     * 从redis中获取权限ids
     *
     * */
    private String getRedisAuthIds(String key,String token) throws Exception {
        String idsStr = redisManager.getString(key + token);
        return idsStr;
    }

    /**
     * 给RequestBody统一设置值
     * @return
     */
//    private JSONObject setRequestBodyVal(JSONObject requestEntityJson, String cacheUserInfo) {
//        SysUser sysUser = JSONArray.parseObject(cacheUserInfo, SysUser.class);
//        //用户类型 0 运营用户 1 商家用户 2店铺用户 3供应商用户
//        Integer type = sysUser.getType();
//        if (type == 0) {
//            //运营方ID
//            requestEntityJson.put(ConstantClassField.DEPT_ID, sysUser.getId());
//        } else if (type == 1) {
//            requestEntityJson.put(ConstantClassField.MERCHANT_ID, sysUser.getMerchantId());
//            requestEntityJson.put(ConstantClassField.MERCHANT_NAME, sysUser.getUsername());
//        } else if (type == 2) {
//            requestEntityJson.put(ConstantClassField.MERCHANT_ID, sysUser.getMerchantId());
//            requestEntityJson.put(ConstantClassField.STORE_ID, sysUser.getStoreId());
//            requestEntityJson.put(ConstantClassField.STORE_NAME, sysUser.getUsername());
//        }
//
//        //创建人名称
//        requestEntityJson.put(ConstantClassField.CREATOR_NAME, sysUser.getUsername());
//        //修改人名称
//        requestEntityJson.put(ConstantClassField.UPDATOR_NAME, sysUser.getUsername());
//        //创建人
//        requestEntityJson.put(ConstantClassField.CREATOR, sysUser.getId());
//        //修改人
//        requestEntityJson.put(ConstantClassField.UPDATOR, sysUser.getId());
//
//        return requestEntityJson;
//    }




}
